<template>
  <el-select :id="id" :name="name" :loading="loading" :value="valueModel"
             :clearable="props.clearable" :placeholder="props.placeholder"
             v-model="valueModel" @change="onChange"
             :popper-options="popper_options">
    <el-option v-if="props.selectAll" label="- 查询全部 -" value=""></el-option>
    <el-option v-for="item in options_" :key="item.value"
               :label="item.label" :value="item.value"></el-option>
  </el-select>
</template>

<script setup>
import {ref, watch, inject} from 'vue';

import setting from "@/widget/provider/setting";
import Layers from "@/lang/layers/index";
import Asserts from "@/lang/core/asserts";
import {usePopperOptions} from "@/widget/use/use-popper-options.js";

/**
 * 下拉框
 *
 * 这个版本的 el-select 有 bug，无法通过全局控制 size，而且还会报错（由 popper-options 引起）
 */
const props = defineProps({
    // 字段名
    name: {type: String}
    // 默认值，注意 value 是单向输入，需要通过 change 事件侦听变化
    , value: {type: [Boolean, Number, String], default: undefined}
    // 数据字典
    , options: {type: [Array, String], default: undefined}
    // 文字提示
    , placeholder: {type: String, default: ''}
    // 选中全部
    , selectAll: {type: Boolean, default: false}

    // 可清除
    , clearable: {type: Boolean, default: true}
    // 查询参数
    , where: {type: Object, default: undefined}
    // 远程数据字典
    , provider: {type: Function, default: setting.queryDictionary}
});

// Emits
const emit = defineEmits(['change']);

/**
 * 组件使用的对象模型
 *
 * @type {FastForm}
 */
const fast_form = inject('fast_form');

/**
 * 组件使用的对象模型
 *
 * @type {FormInput}
 */
const input = fast_form.getFormInput(props.name);
Asserts.notBlank(input, 'form input is undefined:' + props.name);

// 组件 ID
const id = ref(input.id);

// 弹窗配置，没这玩意儿会报错
const popper_options = usePopperOptions();

// 定义要触发的事件，用于更新 v-model 的值
const valueModel = ref(props.value);

// 数据加载状态
const loading = ref(false);

// 数据字典
const options_ = ref([]);

/**
 * 监听父组件传递的 value 变化
 *
 * 如果发生变化，通知到 FormInput，由 FormInput 进行业务流转
 */
watch(() => props.value, (val) => {
    input.setValue(val);
});

/**
 * 监听父组件传递的 options 变化
 *
 * 如果发生变化，更新下拉框的选项
 */
watch(() => props.options, (val) => {
    setOptions(val)
});

/**
 * 监听父组件传递的 where 变化
 *
 * 如果发生变化，将 where 作为参数，触发刷新函数
 */
watch(() => props.where, (val) => {
    reload(val);
});

/**
 * 用户输入变换事件
 *
 * 通知到 FormInput，由 FormInput 进行业务流转
 *
 * @param val
 */
const onChange = (val) => {
    emit('change', val);
    input.changeValue(val);
}

/**
 * 数据受控函数
 *
 * 数据发生变化的时候，会通知到当前组件
 *
 * @see FormInput
 * @param val
 */
const onChangeValue = (val) => {
    valueModel.value = val;
}

/**
 * 设值数据字典
 *
 * @param val 字典
 */
const setOptions = (val) => {
    if (Layers.isEmpty(val)) {
        options_.value = [];
    } else if (Array.isArray(val)) {
        options_.value = val;
    } else if (typeof val === 'string') {
        reload(val);
    }
}

/**
 * 查询远程数据字典
 */
const reload = (params) => {
    loading.value = true;
    props.provider(params).then(ret => {
        options_.value = ret.list;
    }).finally(() => {
        loading.value = false;
    });
}

// 初始化：设置下拉选项
{
    if (Layers.isNotBlank(props.options)) {
        // 下拉数据选项
        setOptions(props.options);
    } else if (Layers.isNotBlank(props.where)) {
        // 查询远程数据字典
        reload(props.where);
    }

    // 通知到 FormInput，由 FormInput 进行业务流转
    input.setValue(props.value);
}

// 注册输入组件侦听
input.setDom({onChangeValue})
</script>